import { Config, Inject, Provide } from '@midwayjs/decorator';
import { BaseService, CoolCommException } from '@cool-midway/core';
import { BizWorkerListEntity } from '../entity/list';
import { BizWorkerIntroduceEntity } from '../entity/introduce';
import { BizWorkerWorkDatesEntity } from '../entity/workDates';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { BizCustomerListService } from '../../bizCustomer/service/list';
import { BizWxService } from '../../bizCustomer/service/wx';
import { formatDate } from '../../../comm/date';

/**
 * 师傅表服务
 */
@Provide()
export class BizWorkerListAppService extends BaseService {
  @Inject()
  bizCustomerListService: BizCustomerListService;
  @Inject()
  bizWxService: BizWxService;

  @InjectEntityModel(BizWorkerListEntity)
  bizWorkerListEntity: Repository<BizWorkerListEntity>;
  @InjectEntityModel(BizWorkerIntroduceEntity)
  bizWorkerIntroduceEntity: Repository<BizWorkerIntroduceEntity>;
  @InjectEntityModel(BizWorkerWorkDatesEntity)
  bizWorkerWorkDatesEntity: Repository<BizWorkerWorkDatesEntity>;

  async bindWx(accountInf: any, wxInf: any) {
    const { account, password } = accountInf;
    const userInfo = await this.bizWorkerListEntity.findOneBy({
      account,
      password,
    });

    if (userInfo) {
      const { id, wechatOpenId } = userInfo;

      const { code, encryptedData, iv } = wxInf;
      const session = await this.bizWxService.miniSession(code);
      const { errcode, errmsg, session_key, openid, unionid } = session;
      if (errcode) {
        throw new CoolCommException(`登录失败 ${errmsg}`);
      }

      /* 获取token和用户id */
      const getResult = async () => {
        return {
          id,
          token: await this.bizCustomerListService.token({ id }),
        };
      };

      if (wechatOpenId !== '') {
        // 账号存在登录记录

        if (wechatOpenId === openid) {
          // 就是本人

          return await getResult();
        } else {
          // 非本人

          throw new CoolCommException(
            `当前账号已绑定其他师傅的终端小程序！请检查账号信息无误后再尝试登录`
          );
        }
      } else {
        // 账号没有被登录过

        const sameOpenIdUserInfo = await this.bizWorkerListEntity.findOneBy({
          wechatOpenId: openid,
        });

        if (sameOpenIdUserInfo) {
          // openid 已绑定了其他账号

          throw new CoolCommException(`您已绑定其他账号！`);
        } else {
          // 初次登录 绑定openid

          await this.bizWorkerListEntity.update(id, {
            wechatOpenId: openid,
          });
          return await getResult();
        }
      }
    } else {
      throw new CoolCommException(`账号或密码错误！`);
    }
  }

  async updatePassword(
    workerId: number,
    passwordOld: string,
    passwordNew: string
  ) {
    const inf = await this.bizWorkerListEntity.findOneBy({ id: workerId });

    if (!inf) {
      throw new CoolCommException(`用户信息错误！`);
    } else if (inf.password === passwordOld) {
      await this.bizWorkerListEntity.update(workerId, {
        password: passwordNew,
      });
      return { workerId };
    } else {
      throw new CoolCommException(`原密码错误！`);
    }
  }

  async info(id: any, infoIgnoreProperty?: string[]): Promise<any> {
    const [workerInfo, workerIntroduce, workerWorkDates] = await Promise.all([
      this.bizWorkerListEntity.findOneBy({ id, status: 1 }),
      this.bizWorkerIntroduceEntity.findOneBy({ workerId: id }),
      this.bizWorkerWorkDatesEntity.findBy({ workerId: id }),
    ]);

    if (workerInfo) {
      this.clearNoNeedFieldForWorkerInf(workerInfo);

      workerInfo['introduce'] = workerIntroduce?.rich || '';
      workerInfo['workDates'] = workerWorkDates.map(v => {
        return {
          id: v.id,
          startDate: v.startDate,
          endDate: v.endDate,
        };
      });
    }

    return workerInfo;
  }

  getAreaAllDateString(start: string, end: string) {
    let startTimmer = new Date(start).getTime();
    const endTimmer = new Date(end).getTime();
    const days = [];
    while (startTimmer <= endTimmer) {
      days.push(formatDate(new Date(startTimmer)));
      startTimmer += 86400000;
    }
    return days;
  }

  /* 获取师傅表和对应的工期表数据 */
  async getWorkerAndWorkDateInf(opt: any) {
    /*
      id name workType 基础条件
    */
    const { id, name, workType } = opt;

    let whereSql = '';
    for (let key in opt) {
      let whereSql_ = '';
      switch (key) {
        case 'id': {
          whereSql_ = id !== undefined ? `W.id = ${id}` : '';
          break;
        }
        case 'name': {
          whereSql_ = name !== undefined ? `W.name like '%${name}%'` : '';
          break;
        }
        case 'workType': {
          whereSql_ = workType !== undefined ? `W.workType = ${workType}` : '';
          break;
        }
        default: {
          break;
        }
      }
      if (whereSql) {
        whereSql_ && (whereSql += ` && ` + whereSql_);
      } else {
        whereSql = whereSql_;
      }
    }

    return await this.nativeQuery(`
      SELECT
        W.*,
        JSON_ARRAYAGG(JSON_OBJECT(
          's',
          WD.startDate,
          'e',
          WD.endDate
        )) AS workDates
      FROM
        biz_worker_list W
      LEFT JOIN
        biz_worker_work_dates WD ON W.id = WD.workerId
      WHERE
        ${whereSql}
      GROUP BY
        W.id
      ORDER BY W.id DESC;
    `);
  }

  /* 根据用户所选工期获得不冲突的师傅列表 */
  getNotOverlapWorkerByDateArea(
    allWorkerAndWorkDateInf: any[],
    startDate: string,
    endDate: string
  ) {
    const days = this.getAreaAllDateString(startDate, endDate);
    const list: any[] = [];
    allWorkerAndWorkDateInf.forEach((worker: any) => {
      const allWDs = []; // 当前师傅所有工期的日期数组
      worker.workDates.forEach((workDate: any) => {
        const { s, e } = workDate;
        if (s && e) allWDs.push(...this.getAreaAllDateString(s, e));
      });
      worker.workDates = allWDs;

      let 工作重合天数 = 0;
      days.forEach((day: string) => {
        if (allWDs.includes(day)) {
          工作重合天数++;
        }
      });
      if (工作重合天数 <= 0) {
        // 工作不可重合
        list.push(worker);
      }
    });

    return list;
  }

  async searchWorkers(
    pagination_: any,
    fieldEq: any
  ): Promise<{
    list: any;
    pagination: { page: number; size: number; total: number };
  }> {
    const { page, size } = pagination_;
    const { startDate, endDate, workType, name } = fieldEq;

    const allWorkerAndWorkDateInf = await this.getWorkerAndWorkDateInf({
      name,
      workType,
    });
    // console.log(JSON.stringify(allWorkerAndWorkDateInf));

    let list = this.getNotOverlapWorkerByDateArea(
      allWorkerAndWorkDateInf,
      startDate,
      endDate
    );
    list = list.slice(0 * page, size);

    list.forEach((worker: any) => {
      this.clearNoNeedFieldForWorkerInf(worker);
    });

    return {
      list,
      pagination: {
        page,
        size,
        total: list.length,
      },
    };
  }

  async checkWorkerCanWork(
    workerId: number,
    startDate: string,
    endDate: string,
    needData: boolean
  ) {
    const allWorkerAndWorkDateInf = await this.getWorkerAndWorkDateInf({
      id: workerId,
    });

    const list = this.getNotOverlapWorkerByDateArea(
      allWorkerAndWorkDateInf,
      startDate,
      endDate
    );

    if (list.length) {
      const worker = list[0];
      this.clearNoNeedFieldForWorkerInf(worker);

      return needData ? worker : Boolean(worker);
    }
    return needData ? null : false;
  }

  clearNoNeedFieldForWorkerInf(worker: any) {
    delete worker.createTime;
    delete worker.updateTime;
    delete worker.status;
    delete worker.account;
    delete worker.password;
    delete worker.notes;
    delete worker.wechatOpenId;
    delete worker.workDates;
  }
}
